/***************************************************************************
 *    
 *      Copyright (c) 2009,2010 KaiTrade LLC (registered in Delaware)
 *                     All Rights Reserved Worldwide
 *
 * STRICTLY PROPRIETARY and CONFIDENTIAL
 *
 * WARNING:  This file is the confidential property of KaiTrade LLC For
 * use only by those with the express written permission and license from
 * KaiTrade LLC.  Unauthorized reproduction, distribution, use or disclosure 
 * of this file or any program (or document) is prohibited. 
 * 
 ***************************************************************************/
using System;

//using Clifton.Collections.Generic;

namespace K2AlgoSet
{
    public class SimpleMovingAverage :  ExpressionBase, IMovingAverage
	{
        
		private CircularList<float> samples;
		protected float total;
        private string m_BarField = KaiTrade.Interfaces.TSBarField.HLC3;
        public SimpleMovingAverage()
        {
            m_Name = "KMVA";
        }

		/// <summary>
		/// Get the average for the current number of samples.
		/// </summary>
		public float Average
		{
			get
			{
				if (samples.Count == 0)
				{
					throw new ApplicationException("Number of samples is 0.");
				}

				return total / samples.Count;
			}
		}

		/// <summary>
		/// Constructor, initializing the sample size to the specified number.
		/// </summary>
		public SimpleMovingAverage(int numSamples)
		{
			if (numSamples <= 0)
			{
				throw new ArgumentOutOfRangeException("numSamples can't be negative or 0.");
			}

			samples = new CircularList<float>(numSamples);
			total = 0;
            m_Log = log4net.LogManager.GetLogger("PlugIn");
		}


        private void SetCurrentValue(KaiTrade.Interfaces.TSItem myBar)
        {
            try
            {
                switch (m_BarField)
                {
                    case KaiTrade.Interfaces.TSBarField.HLC3:
                        this.SetCurrentValue((float)myBar.HLC3);
                        break;
                    case KaiTrade.Interfaces.TSBarField.OPEN:
                        this.SetCurrentValue((float)myBar.Open);
                        break;
                    case KaiTrade.Interfaces.TSBarField.CLOSE:
                        this.SetCurrentValue((float)myBar.Close);
                        break;
                    case KaiTrade.Interfaces.TSBarField.HIGH:
                        this.SetCurrentValue((float)myBar.High);
                        break;
                    case KaiTrade.Interfaces.TSBarField.LOW:
                        this.SetCurrentValue((float)myBar.Low);
                        break;
                    default:
                        this.SetCurrentValue((float)myBar.HLC3);
                        break;
                }



            }
            catch (Exception myE)
            {
                m_Log.Error("AddSample", myE);
            }
        }
        int kak = 0;
        public void SetCurrentValue(float val)
        {
            
            total -= samples[kak];
            samples[kak] = val;
            total += val;
            
        }
		/// <summary>
		/// Adds a sample to the sample collection.
		/// </summary>
		public void AddSample(float val)
		{
			if (samples.Count == samples.Length)
			{
				total -= samples.Value;
			}

			samples.Value = val;
			total += val;
            kak = samples.Index;
			samples.Next();
		}

		/// <summary>
		/// Clears all samples to 0.
		/// </summary>
		public void ClearSamples()
		{
			total = 0;
			samples.Clear();
		}

		/// <summary>
		/// Initializes all samples to the specified value.
		/// </summary>
		public void InitializeSamples(float v)
		{
			samples.SetAll(v);
			total = v * samples.Length;
		}

        protected override void parseExpression(string myExpression)
        {
            try
            {
                string[] myParms = myExpression.Split(',');
                string myName = myParms[0];
                string mySize = myParms[1];
                if (myParms.Length >= 3)
                {
                    m_BarField = myParms[2];
                }
                samples = new CircularList<float>(int.Parse(mySize));

            }
            catch(Exception myE)
            {
                m_Log.Error("parseExpression", myE);
            }
        }

        #region StatExpression Members

       

        public override double Value
        {
            get { return (double)this.Average; }
        }


        private void AddSample(KaiTrade.Interfaces.TSItem myBar)
        {
            try
            {
                switch (m_BarField)
                {
                    case KaiTrade.Interfaces.TSBarField.HLC3:
                        this.AddSample((float)myBar.HLC3);
                        break;
                    case KaiTrade.Interfaces.TSBarField.OPEN:
                        this.AddSample((float)myBar.Open);
                        break;
                    case KaiTrade.Interfaces.TSBarField.CLOSE:
                        this.AddSample((float)myBar.Close);
                        break;
                    case KaiTrade.Interfaces.TSBarField.HIGH:
                        this.AddSample((float)myBar.High);
                        break;
                    case KaiTrade.Interfaces.TSBarField.LOW:
                        this.AddSample((float)myBar.Low);
                        break;
                    default:
                         this.AddSample((float)myBar.HLC3);
                        break;
                }
               


            }
            catch (Exception myE)
            {
                m_Log.Error("AddSample", myE);
            }
        }
        /// <summary>
        /// Evaluate the expression on the current data, normally should use
        /// the last complete item/bar - setting bUseCurrent bar will cause
        /// the evaluation to include the bar being added to, that has yet to
        /// end.
        /// </summary>
        public override void EvaluateAdded(bool bUseCurrentBar) 
        {
            try
            {

                if (bUseCurrentBar)
                {
                    // since we are using the current bar then just replace the
                    // current value of the moving average - note this can change
                    // manay times per period
                    KaiTrade.Interfaces.TSItem myBar = m_TSSet.CurrentItem;
                    if (myBar != null)
                    {
                        this.AddSample(myBar);
                    }
                }
                else
                {
                    // Since we are using the last complete just roll that into the
                    // average
                    KaiTrade.Interfaces.TSItem myBar = m_TSSet.LastCompleteItem;
                    if (myBar != null)
                    {
                        this.AddSample(myBar);
                    }
                }

            }
            catch (Exception myE)
            {
                m_Log.Error("Evaluate", myE);
            }
        }

        public override void EvaluateUpdate(bool bUseCurrentBar)
        {
            try
            {

                if (bUseCurrentBar)
                {
                    // since we are using the current bar then just replace the
                    // current value of the moving average - note this can change
                    // manay times per period
                    KaiTrade.Interfaces.TSItem myBar = m_TSSet.CurrentItem;
                    if (myBar != null)
                    {
                        this.SetCurrentValue(myBar);
                    }
                }
                else
                {
                    /*
                    KaiTrade.Interfaces.TSItem myBar = m_TSSet.LastCompleteItem;
                    if (myBar != null)
                    {
                        this.SetCurrentValue((float)myBar.HLC3);
                    }
                     */
                }

            }
            catch (Exception myE)
            {
                m_Log.Error("Evaluate", myE);
            }
        }

        #endregion
    }
}
